package org.particlethink.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import kotlin.Pair;
import org.particlethink.auth.DefaultUser;
import org.particlethink.context.Context;
import org.particlethink.context.DefaultContext;
import org.particlethink.customer.Consumer;
import org.particlethink.dto.DeliverStatusAndCount;
import org.particlethink.entry.DeliverStatus;
import org.particlethink.entry.OrderStatus;
import org.particlethink.entry.PlanTyp;
import org.particlethink.exception.NoPermissionException;
import org.particlethink.exception.StatusException;
import org.particlethink.mapper.*;
import org.particlethink.model.Acceptance;
import org.particlethink.model.*;
import org.particlethink.request.AcceptSubOrderRequest;
import org.particlethink.request.DeliveryGood;
import org.particlethink.response.DeliverExportResponse;
import org.particlethink.response.DeliverResponse;
import org.particlethink.response.DeliverStatusCountResponse;
import org.particlethink.service.ConsumerService;
import org.particlethink.service.SubOrderService;
import org.particlethink.service.listen.event.ConfirmDeliverEvent;
import org.particlethink.service.listen.event.OrderAllShipmentEvent;
import org.particlethink.utils.ListUtilsKt;
import org.particlethink.utils.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class SubOrderServiceImpl implements SubOrderService {
    @Autowired
    private ConsumerService consumerService;

    @Autowired
    private DeliverMapper deliverMapper;

    @Autowired
    private AcceptanceMapper acceptanceMapper;

    @Autowired
    private ObjectionReasonMapper objectionReasonMapper;

    @Autowired
    private OrderMapper orderPlanMapper;

    @Autowired
    private ApplicationEventPublisher eventPublisher;
    @Autowired
    private PlanMaterialMapper planMaterialMapper;

    @Autowired
    private ProjectMapper projectMapper;

    @Autowired
    private SupplierMapper supplierMapper;

    @Autowired
    private CategoryMapper categoryMapper;

    @Autowired
    private SupplierUserMapper supplierUserMapper;

    @Autowired
    private ProjectUserMapper projectUserMapper;

    @Override
    @Transactional
    public void reject(List<Integer> projectIds, Integer userId, Integer subOrderID) {

        Deliver deliver = findDeliver(subOrderID);
        if (!deliver.canReject()) {
            return;
        }

        if (!projectIds.contains(deliver.getProjectId())) {
            throw new NoPermissionException();
        }

        // 作废
        deliver.setStatus(DeliverStatus.Discard);
        deliver.setDiscardDate(new Date());
        deliverMapper.updateByPrimaryKeySelective(deliver);
        eventPublisher.publishEvent(new ConfirmDeliverEvent(deliver.getId()));
    }

    @Override
    @Transactional
    public void accept(List<Integer> projectIds, Integer userId, AcceptSubOrderRequest request) {
        Deliver deliver = findDeliver(request.getSubOrderId());
        if (!projectIds.contains(deliver.getProjectId())) {
            throw new NoPermissionException();
        }


        // 验证权限
        if (!deliver.canAccept()) {
            throw new StatusException();
        }


        Acceptance acceptance = request.toAcceptance(deliver.getId(), userId);
        acceptanceMapper.insert(acceptance);


        deliver.setProjectRemark(acceptance.getSuggestion());
        deliver.setStatus(DeliverStatus.UnConfirmed);
        deliver.setAcceptanceId(acceptance.getId());
        deliver.setAcceptanceAt(new Date());


        deliverMapper.updateByPrimaryKeySelective(deliver);

        List<PlanMaterial> planMaterials = planMaterialMapper.selectByPlanIDAndTyp(deliver.getId(), PlanTyp.Deliver);

        Map<Integer, AcceptSubOrderRequest.AcceptGoodsInfo> map = ListUtilsKt.map(request.getGoodsInfo(), AcceptSubOrderRequest.AcceptGoodsInfo::getPlanMaterialId);

        planMaterials = planMaterials.stream().filter(planMaterial -> {
            return map.containsKey(planMaterial.getId());
        }).map(planMaterial -> {
            AcceptSubOrderRequest.AcceptGoodsInfo acceptGoodsInfo = map.get(planMaterial.getId());
            planMaterial.setCompleteNum(acceptGoodsInfo.getGoodsNum());
            planMaterial.setRemark(acceptGoodsInfo.getRemark());
            return planMaterial;
        }).collect(Collectors.toList());
        if (planMaterials.isEmpty()) {
            return;
        }
        planMaterialMapper.updateCompleteNum(planMaterials);

        eventPublisher.publishEvent(new ConfirmDeliverEvent(deliver.getId()));
    }

    @Override
    public void edit(List<Integer> projectIds, AcceptSubOrderRequest request, Integer id) {
        // 发货单
        Deliver deliver = findDeliver(id);

        if (!projectIds.contains(deliver.getProjectId())) {
            throw new NoPermissionException();
        }

        // 验证权限
        if (!deliver.canEdit()) {
            throw new StatusException();
        }

        Acceptance acceptance = acceptanceMapper.selectByPrimaryKey(deliver.getAcceptanceId());
        acceptance = request.updateAcceptance(acceptance);
        acceptanceMapper.updateByPrimaryKey(acceptance);

        deliver.setStatus(DeliverStatus.UnConfirmed);
        deliver.setAcceptanceId(acceptance.getId());
        deliver.setAcceptanceAt(new Date());
        deliverMapper.updateByPrimaryKeySelective(deliver);

        List<PlanMaterial> planMaterials = planMaterialMapper.selectByPlanIDAndTyp(deliver.getId(), PlanTyp.Deliver);

        Map<Integer, AcceptSubOrderRequest.AcceptGoodsInfo> map = ListUtilsKt.map(request.getGoodsInfo(), AcceptSubOrderRequest.AcceptGoodsInfo::getPlanMaterialId);

        planMaterials = planMaterials.stream().filter(planMaterial -> {
            return map.containsKey(planMaterial.getId());
        }).map(planMaterial -> {
            AcceptSubOrderRequest.AcceptGoodsInfo acceptGoodsInfo = map.get(planMaterial.getId());
            planMaterial.setCompleteNum(acceptGoodsInfo.getGoodsNum());
            planMaterial.setRemark(acceptGoodsInfo.getRemark());
            return planMaterial;
        }).collect(Collectors.toList());
        if (planMaterials.isEmpty()) {
            return;
        }
        planMaterialMapper.updateCompleteNum(planMaterials);
    }

    @Override
    public void preserve(AcceptSubOrderRequest request, Integer userId) {
        Consumer consumer = consumerService.buildConsumer(userId);

        // 发货单
        Deliver deliver = findDeliver(request.getSubOrderId());

        // 验证权限
        if (!deliver.canAccept()) {
            return;
        }

        if (!Objects.equals(deliver.getProjectId(), consumer.getProjectId())) {
            // todo 对应的异常处理逻辑
            return;
        }
        deliverMapper.updateByPrimaryKeySelective(deliver);
    }

    @Override
    public void confirm(Integer userID, Integer subOrderID) {
        Deliver deliver = findDeliver(subOrderID);
        deliver.setStatus(DeliverStatus.Warehoused);
        deliver.setConfirmAt(new Date());
        deliverMapper.updateByPrimaryKeySelective(deliver);

        Order order = orderPlanMapper.selectByPrimaryKey(deliver.getOrderId());
        if (!order.getAllShipment()) {
            return;
        }
        List<Deliver> delivers = deliverMapper.selectByOrderId(order.getId());
        if (!delivers.stream().allMatch(t -> t.getStatus() == DeliverStatus.Warehoused || t.getStatus() == DeliverStatus.Reconciled)) {
            return;
        }
        order.setStatus(OrderStatus.Done);
        orderPlanMapper.updateByPrimaryKeySelective(order);


//        Map<Integer, PlanMaterial> orderPlanMaterialsMap = ListUtilsKt.map(planMaterialMapper.selectByPlanIDAndTyp(deliver.getOrderId(), PlanTyp.Order), PlanMaterial::getMaterialId);
//        List<PlanMaterial> subOrderPlanMaterials = planMaterialMapper.selectByPlanIDAndTyp(deliver.getId(), PlanTyp.Deliver);
//        subOrderPlanMaterials.forEach(planMaterial -> {
//            PlanMaterial pm = orderPlanMaterialsMap.get(planMaterial.getMaterialId());
//            pm.setCompleteNum(pm.getCompleteNum() + planMaterial.getCompleteNum());
//            orderPlanMaterialsMap.put(planMaterial.getMaterialId(), pm);
//        });
//        planMaterialMapper.updateCompleteNum(new ArrayList<>(orderPlanMaterialsMap.values()));

        // todo 判断是否所有物料都已出库完成，如果都已经出库完成则需要修改订单状态为完成
//        eventPublisher.publishEvent(new ConfirmDeliverEvent(subOrderID));

//        Order order = this.orderPlanMapper.selectByPrimaryKey(deliver.getOrderId());

//        eventPublisher.publishEvent(new OrderAllShipmentEvent(order));
    }

    @Override
    public void objection(Integer userID, Integer subOrderID, String objectionReason) {
        Deliver deliver = findDeliver(subOrderID);
        deliver.setStatus(DeliverStatus.Objection);
        deliver.setObjectionDate(new Date());
        deliver.setObjectionReason(objectionReason);
        deliverMapper.updateByPrimaryKeySelective(deliver);

        // 保存异议原因
//        ObjectionReason objectionReasonObj = new ObjectionReason();
//        objectionReasonObj.setReason(objectionReason);
//        objectionReasonObj.setObjectionType(ObjectionType.SubOrder);
//        objectionReasonObj.setCorrelationId(subOrderID);
//        objectionReasonMapper.insert(objectionReasonObj);
    }

    private String GetDeliverNo(Integer orderId, String orderNo) {
        Integer count = this.deliverMapper.countByOrderId(orderId);

        return orderNo + String.format("%02d", count + 1);
    }

    @Override
    @Transactional
    public void create(
            Integer userID,
            Integer orderID,
            List<DeliveryGood> deliveryGoods,
            Date finishTime,
            String remark,
            String receiverName,
            String receiverPhone,
            String receiverAddress
    ) {

        Consumer consumer = consumerService.buildConsumer(userID);
        if (!consumer.isSupplierConsumer()) {
            // todo 抛出相应异常
            return;
        }


        Order order = orderPlanMapper.selectByPrimaryKey(orderID);


        if (!order.canDeliver()) {
            throw new StatusException();
        }

        String no = GetDeliverNo(order.getId(), order.getNo());


        Deliver deliver = new Deliver(order, userID, finishTime, remark, no);
        deliver.setReceiverName(receiverName);
        deliver.setReceiverPhone(receiverPhone);
        deliver.setReceiverAddress(receiverAddress);

        deliverMapper.insert(deliver);


        List<Integer> planMaterialIds = deliveryGoods.stream().map(DeliveryGood::getPlanMaterialId).collect(Collectors.toList());


        List<PlanMaterial> planMaterials = this.planMaterialMapper.selectByIds(planMaterialIds);

        Map<Integer, PlanMaterial> planMaterialMap = ListUtilsKt.map(planMaterials, PlanMaterial::getId);

        List<PlanMaterial> planMaterialList = deliveryGoods.stream().map((t) -> {
            PlanMaterial planMaterial = planMaterialMap.get(t.getPlanMaterialId());
            return new PlanMaterial(
                    planMaterial.getMaterialId(),
                    deliver.getId(),
                    PlanTyp.Deliver,
                    t.getGoodsNum(),
                    planMaterial.getSupplierId(),
                    planMaterial.getPurpose(),
                    t.getRemark(),
                    t.getGoodsNum()
            );
        }).collect(Collectors.toList());

        this.planMaterialMapper.batchInsert(planMaterialList);

        // 尝试更新订单状态
        boolean needUpdate = false;
        if (order.getStatus() == OrderStatus.Unshipped) {
            needUpdate = true;
            order.setStatus(OrderStatus.InProgress);
        }

        //更新order
//        List<Deliver> delivers = this.deliverMapper.selectByOrderId(orderID);
//        List<Integer> deliverIds = delivers.stream().map(Deliver::getOrderId).distinct().collect(Collectors.toList());
//        deliverIds


        if (needUpdate) {
            orderPlanMapper.updateByPrimaryKeySelective(order);
        }

        eventPublisher.publishEvent(new ConfirmDeliverEvent(deliver.getId()));
    }

    @Override
    public PageInfo<DeliverResponse> queryDeliver(
            DefaultUser defaultUser,
            String managementLevel,
            Integer projectId,
            String deliverNo,
            String orderNo,
            Integer categoryId,
            String carNumber,
            String supplierUserName,
            String acceptanceUserName,
            Date acceptanceStart,
            Date acceptanceEnd,
            Integer supplierId,
            DeliverStatus status,
            Boolean shouldBilled,
            Date submitStart,
            Date submitEnd,
            String searchKey,
            Integer pageNum,
            Integer pageSize
    ) {
        if (pageNum == null) {
            pageNum = 1;
        }
        if (pageSize == null) {
            pageSize = 20;
        }
        User user = defaultUser.getUser();

        List<Project> projects = null;
        if (ObjectUtils.isEmpty(projectId)) {
            ArrayList<Integer> projectIds = new ArrayList<>();
            projectIds.add(projectId);

            projects = this.projectMapper.selectByIds(user.getToken(), projectIds);

        } else {
            projects = this.projectMapper.list(user.getToken(), "", managementLevel, user.getProjectIds());
        }

        if (projects == null || projects.isEmpty()) {
            return new PageInfo<>(Collections.emptyList());
        }
        if (defaultUser.isProjectConsumer() && searchKey != null && !searchKey.isEmpty()) {
            List<Project> newProjects = projects.stream().filter(project -> {
                return project.getName().contains(searchKey);
            }).collect(Collectors.toList());

            if (!newProjects.isEmpty()) {
                projects = newProjects;
            } else {
                return new PageInfo<>(new ArrayList<>());
            }
        }


        List<Supplier> suppliers;

        if (supplierId != null) {
            suppliers = supplierMapper.selectByIds(user.getToken(), Collections.singletonList(supplierId));
        } else {
            suppliers = supplierMapper.selectByIds(user.getToken(), user.getSupplierIds());
        }

        if (defaultUser.isSupplierConsumer() && suppliers.isEmpty()) {
            return new PageInfo<>(Collections.emptyList());
        }


        if (defaultUser.isSupplierConsumer() && searchKey != null && !searchKey.isEmpty()) {
            List<Supplier> newSuppliers = suppliers.stream().filter(supplier -> {
                return supplier.getName().contains(searchKey);
            }).collect(Collectors.toList());

            if (!newSuppliers.isEmpty()) {
                suppliers = newSuppliers;
            } else {
                return new PageInfo<>(new ArrayList<>());
            }
        }

        List<Integer> ids = null;
        if (carNumber != null && !carNumber.isEmpty()) {
            ids = acceptanceMapper.queryAllByCarNumber(carNumber).stream().map(Acceptance::getDeliverId).collect(Collectors.toList());
            if (ids.isEmpty()) {
                return new PageInfo<>(Collections.emptyList());
            }
        }


        List<SupplierUser> creators;
        List<Integer> creatorIds = null;
        if (supplierUserName != null && !supplierUserName.isEmpty()) {
            creators = supplierUserMapper.selectByName(supplierUserName);
            creatorIds = creators.stream().map(SupplierUser::getId).collect(Collectors.toList());
            if (creatorIds.isEmpty()) {
                return new PageInfo<>(Collections.emptyList());
            }
        } else {
            creators = supplierUserMapper.selectAll();
        }

        List<Integer> applicantIds = null;
        if (acceptanceUserName != null && !acceptanceUserName.isEmpty()) {
            applicantIds = projectUserMapper.selectByName(acceptanceUserName).stream().map(ProjectUser::getId).collect(Collectors.toList());
            if (applicantIds.isEmpty()) {
                return new PageInfo<>(Collections.emptyList());
            }
        }

        PageHelper.startPage(pageNum, pageSize);
        PageInfo<Deliver> delivers = new PageInfo<>(deliverMapper.queryDelivers(
                ids,
                projects.stream().map(Project::getId).collect(Collectors.toList()),
                suppliers.stream().map(Supplier::getId).collect(Collectors.toList()),
                deliverNo,
                orderNo,
                categoryId,
                carNumber,
                creatorIds,
                applicantIds,
                acceptanceStart,
                acceptanceEnd,
                supplierId,
                status,
                shouldBilled,
                submitStart,
                submitEnd
        ));

        Map<Integer, Project> projectMap = ListUtilsKt.map(projects, Project::getId);

        List<String> categoryIds = delivers.getList().stream().map(Deliver::getCategoryId).collect(Collectors.toList());
        List<Category> categories = categoryMapper.selectByIds(user.getToken(), categoryIds.stream().distinct().collect(Collectors.toList()));
        Map<String, Category> categoryMap = ListUtilsKt.map(categories, Category::getId);

        Map<Integer, SupplierUser> creatorMap = ListUtilsKt.map(creators, SupplierUser::getId);

        List<Integer> deliverIds = delivers.getList().stream().map(Deliver::getId).collect(Collectors.toList());
        List<Acceptance> acceptances = this.acceptanceMapper.selectByDeliverIds(deliverIds);
        Map<Integer, Acceptance> acceptanceMap = ListUtilsKt.map(acceptances, Acceptance::getDeliverId);


        Map<Integer, ProjectUser> projectUserMap = new HashMap<>();
        List<Integer> acceptanceCreatorIds = acceptances.stream().map(Acceptance::getCreatorId).distinct().collect(Collectors.toList());
        if (acceptanceCreatorIds != null && !acceptanceCreatorIds.isEmpty()) {
            List<ProjectUser> projectUsers = projectUserMapper.selectByIds(acceptanceCreatorIds);
            projectUserMap = ListUtilsKt.map(projectUsers, ProjectUser::getId);
        }


        Map<Integer, Supplier> supplierMap = ListUtilsKt.map(suppliers, Supplier::getId);


        Map<Integer, ProjectUser> finalProjectUserMap = projectUserMap;
        return delivers.convert(deliver -> {
                    Acceptance acceptance = acceptanceMap.get(deliver.getId());
                    ProjectUser projectUser = null;
                    if (acceptance != null) {
                        projectUser = finalProjectUserMap.get(acceptance.getCreatorId());
                    }


                    return new DeliverResponse(
                            deliver,
                            projectMap.get(deliver.getProjectId()),
                            categoryMap.get(deliver.getCategoryId()),
                            creatorMap.get(deliver.getCreatorId()),
                            supplierMap.get(deliver.getSupplierId()),
                            acceptance,
                            projectUser);
                }
        );
    }

    public PageInfo<DeliverResponse> queryNo(User user, DeliverStatus status, String no) {


        List<Deliver> delivers = deliverMapper.selectByNo(no, status);
        if (delivers == null || delivers.isEmpty()) {
            return new PageInfo<>(new ArrayList<>());
        }
        List<Integer> projectIds = delivers.stream().map(Deliver::getProjectId).distinct().collect(Collectors.toList());
        List<Project> projects = this.projectMapper.selectByIds(user.getToken(), projectIds);

        Map<Integer, Project> projectMap = ListUtilsKt.map(projects, Project::getId);

        List<String> categoryIds = delivers.stream().map(Deliver::getCategoryId).collect(Collectors.toList());
        List<Category> categories = categoryMapper.selectByIds(user.getToken(), categoryIds.stream().distinct().collect(Collectors.toList()));
        Map<String, Category> categoryMap = ListUtilsKt.map(categories, Category::getId);


        List<Integer> creatorIds = delivers.stream().map(Deliver::getCreatorId).distinct().collect(Collectors.toList());
        List<SupplierUser> creators = this.supplierUserMapper.selectByIds(creatorIds);

        Map<Integer, SupplierUser> creatorMap = ListUtilsKt.map(creators, SupplierUser::getId);
        List<Integer> deliverIds = delivers.stream().map(Deliver::getId).collect(Collectors.toList());
        List<Acceptance> acceptances = this.acceptanceMapper.selectByDeliverIds(deliverIds);
        Map<Integer, Acceptance> acceptanceMap = ListUtilsKt.map(acceptances, Acceptance::getDeliverId);

        List<Integer> supplierIds = delivers.stream().map(Deliver::getSupplierId).distinct().collect(Collectors.toList());
        List<Supplier> suppliers = this.supplierMapper.selectByIds(user.getToken(), supplierIds);
        Map<Integer, Supplier> supplierMap = ListUtilsKt.map(suppliers, Supplier::getId);


        Map<Integer, ProjectUser> projectUserMap = new HashMap<>();
        List<Integer> acceptanceCreatorIds = acceptances.stream().map(Acceptance::getCreatorId).distinct().collect(Collectors.toList());
        if (acceptanceCreatorIds != null && !acceptanceCreatorIds.isEmpty()) {
            List<ProjectUser> projectUsers = projectUserMapper.selectByIds(acceptanceCreatorIds);
            projectUserMap = ListUtilsKt.map(projectUsers, ProjectUser::getId);
        }

        Map<Integer, ProjectUser> finalProjectUserMap = projectUserMap;


        return new PageInfo<>(delivers.stream().map(deliver -> {

                    Acceptance acceptance = acceptanceMap.get(deliver.getId());
                    ProjectUser projectUser = null;
                    if (acceptance != null) {
                        projectUser = finalProjectUserMap.get(acceptance.getCreatorId());
                    }

                    return new DeliverResponse(
                            deliver,
                            projectMap.get(deliver.getProjectId()),
                            categoryMap.get(deliver.getCategoryId()),
                            creatorMap.get(deliver.getCreatorId()),
                            supplierMap.get(deliver.getSupplierId()),
                            acceptance,
                            projectUser
                    );
                }
        ).collect(Collectors.toList()));
    }


    public List<DeliverExportResponse> export(
            User user,
            String managementLevel,
            Integer projectId,
            String deliverNo,
            String orderNo,
            Integer categoryId,
            String carNumber,
            String supplierUserName,
            String acceptanceUserName,
            Date acceptanceStart,
            Date acceptanceEnd,
            Integer supplierId,
            DeliverStatus status,
            Date submitStart,
            Date submitEnd
    ) {



        List<Project> projects = null;
        if (ObjectUtils.isEmpty(projectId)) {
            ArrayList<Integer> projectIds = new ArrayList<>();
            projectIds.add(projectId);

            projects = this.projectMapper.selectByIds(user.getToken(), projectIds);

        } else {
            projects = this.projectMapper.list(user.getToken(), "", managementLevel, user.getProjectIds());
        }
        if (projects.isEmpty()) {
            return new ArrayList<>();
        }

        List<Supplier> suppliers;

        if (supplierId != null) {
            suppliers = supplierMapper.selectByIds(user.getToken(), Collections.singletonList(supplierId));
        } else {
            suppliers = supplierMapper.selectByIds(user.getToken(), user.getSupplierIds());
        }

        List<Integer> ids = null;
        if (carNumber != null && !carNumber.isEmpty()) {
            ids = acceptanceMapper.queryAllByCarNumber(carNumber).stream().map(Acceptance::getDeliverId).collect(Collectors.toList());
        }


        List<SupplierUser> creators;
        List<Integer> creatorIds = null;
        if (supplierUserName != null && !supplierUserName.isEmpty()) {
            creators = supplierUserMapper.selectByName(supplierUserName);
            creatorIds = creators.stream().map(SupplierUser::getId).collect(Collectors.toList());
        } else {
            creators = supplierUserMapper.selectAll();
        }
        List<Integer> applicantIds = null;
        if (acceptanceUserName != null && !acceptanceUserName.isEmpty()) {
            applicantIds = projectUserMapper.selectByName(acceptanceUserName).stream().map(ProjectUser::getId).collect(Collectors.toList());
        }

        List<Deliver> delivers = deliverMapper.queryDelivers(ids, projects.stream().map(Project::getId).collect(Collectors.toList()), suppliers.stream().map(Supplier::getId).collect(Collectors.toList()), deliverNo, orderNo, categoryId, carNumber, creatorIds, applicantIds, acceptanceStart, acceptanceEnd, supplierId, status, null, submitStart, submitEnd);

        Map<Integer, Project> projectMap = ListUtilsKt.map(projects, Project::getId);

        List<String> categoryIds = delivers.stream().map(Deliver::getCategoryId).collect(Collectors.toList());
        List<Category> categories = categoryMapper.selectByIds(user.getToken(), categoryIds.stream().distinct().collect(Collectors.toList()));
        Map<String, Category> categoryMap = ListUtilsKt.map(categories, Category::getId);

        Map<Integer, SupplierUser> creatorMap = ListUtilsKt.map(creators, SupplierUser::getId);

        List<Integer> deliverIds = delivers.stream().map(Deliver::getId).collect(Collectors.toList());
        List<Acceptance> acceptances = this.acceptanceMapper.selectByDeliverIds(deliverIds);
        Map<Integer, Acceptance> acceptanceMap = ListUtilsKt.map(acceptances, Acceptance::getId);


        return delivers.stream().map(deliver -> new DeliverExportResponse(
                deliver,
                projectMap.get(deliver.getProjectId()),
                categoryMap.get(deliver.getCategoryId()),
                creatorMap.get(deliver.getCreatorId()),
                acceptanceMap.get(deliver.getId())
        )).collect(Collectors.toList());
    }

    public List<Deliver> queryDeliver(List<DeliverStatus> status, Integer orderID) {
        if (status == null || status.isEmpty()) {
            return deliverMapper.selectByOrderId(orderID);
        }
        return deliverMapper.selectByOrderAndStatuses(orderID, status);
    }

    private Deliver findDeliver(Integer subOrderID) {
        Deliver deliver = new Deliver();
//        deliver.setId(subOrderID);
        deliver = deliverMapper.selectByPrimaryKey(subOrderID);
        return deliver;
    }


    //备注
    public void remark(List<Integer> supplierIds, int deliverId, String remark) {
        Deliver deliver = this.deliverMapper.selectByPrimaryKey(deliverId);
        if (!deliver.canRemark()) {
            return;
        }
        if (!supplierIds.contains(deliver.getSupplierId())) {
            throw new NoPermissionException("你不属于该供货商");
        }

        deliver.setRemark(remark);

        this.deliverMapper.updateByPrimaryKeySelective(deliver);
    }

    //撤回
    public void cancel(List<Integer> projectIds, int deliverId, String remark) {
        Deliver deliver = this.deliverMapper.selectByPrimaryKey(deliverId);
        if (!deliver.canCancel()) {
            return;
        }
        if (!projectIds.contains(deliver.getProjectId())) {
            throw new NoPermissionException("你不属于该项目");
        }

        deliver.setProjectRemark(remark);
        deliver.setStatus(DeliverStatus.UnChecked);

        this.deliverMapper.updateByPrimaryKeySelective(deliver);
    }


    //再次发起
    public void reAccept(List<Integer> projectIds, Integer deliverId) {
        Deliver deliver = this.deliverMapper.selectByPrimaryKey(deliverId);
        if (!deliver.canReAccept()) {
            return;
        }
        if (!projectIds.contains(deliver.getProjectId())) {
            throw new NoPermissionException("你不属于该项目");
        }

        deliver.setStatus(DeliverStatus.UnConfirmed);

        this.deliverMapper.updateByPrimaryKeySelective(deliver);
    }

    @Override
    public DeliverStatusCountResponse countOrdersByStatus(List<Integer> supplierIds, List<Integer> projectIds) {
        List<DeliverStatusAndCount> deliverStatusAndCounts = this.deliverMapper.countByStatus(supplierIds, projectIds);
        Map<DeliverStatus, Integer> deliverStatusIntegerMap = ListUtilsKt.mapKV(deliverStatusAndCounts, (deliverStatusAndCount) -> new Pair<>(deliverStatusAndCount.getStatus(), deliverStatusAndCount.getCount()));

        return new DeliverStatusCountResponse(
                deliverStatusIntegerMap.getOrDefault(DeliverStatus.UnChecked, 0),
                deliverStatusIntegerMap.getOrDefault(DeliverStatus.UnConfirmed, 0),
                deliverStatusIntegerMap.getOrDefault(DeliverStatus.Objection, 0),
                deliverStatusIntegerMap.getOrDefault(DeliverStatus.Warehoused, 0) + deliverStatusIntegerMap.getOrDefault(DeliverStatus.Reconciled, 0)
        );
    }
}
